package com.jzo2o.foundations.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeItem;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.ServeResDTO;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {

    private final IRegionService regionService;

    private final IServeItemService serveItemService;

    @Override
    public PageResult<ServeResDTO> servePage(ServePageQueryReqDTO servePageQueryReqDTO) {
        return PageHelperUtils.selectPage(servePageQueryReqDTO, () -> baseMapper.queryList(servePageQueryReqDTO.getRegionId()));
    }

    @Transactional
    @Override
    public void batchAdd(List<ServeUpsertReqDTO> serveUpsertReqDTOList) {
        //1 业务逻辑判断,区域服务是否都已启用,同一个区域不能出现重复的服务id
        //1-1 传入的参数列表不能为空
        if (CollUtil.isEmpty(serveUpsertReqDTOList)) {
            throw new CommonException("添加的区域服务是不允许为空");
        }
        //1-2 不允许id重复
        Set<Long> serveItemIdSet = serveUpsertReqDTOList.stream()
                .map(ServeUpsertReqDTO::getServeItemId)
                .collect(Collectors.toSet());
        //1-3 区域服务检查是否已启用
        if (serveItemService.lambdaQuery()
                .in(ServeItem::getId, serveItemIdSet)
                .ne(ServeItem::getActiveStatus, FoundationStatusEnum.ENABLE.getStatus()).exists()) {
            throw new ForbiddenOperationException("不允许区域中添加不是启用状态服务项");
        }

        //2 插入数据
        //2-1 构造region-cityCode映射Map
        Set<Long> regionIdSet = serveUpsertReqDTOList.stream()
                .map(ServeUpsertReqDTO::getRegionId)
                .collect(Collectors.toSet());
        Map<Long, String> regionMap = regionService.lambdaQuery().in(Region::getId, regionIdSet).list()
                .stream()
                .collect(Collectors.toMap(Region::getId, Region::getCityCode));

        //2-2 构造要插入的数据
        List<Serve> serveList = BeanUtil.copyToList(serveUpsertReqDTOList, Serve.class);
        serveList.forEach(serve -> serve.setCityCode(regionMap.getOrDefault(serve.getRegionId(), "")));
        //2.3 批量保存： 如果保存的服务项出现违反唯一约束
        try {
            this.saveBatch(serveList);
        } catch (Exception e) {
            //判断当前补货的异常是否数据库唯一约束的异常，如果是则抛出指定的异常，给出异常消息
            if (e instanceof SQLIntegrityConstraintViolationException) {
                throw new ForbiddenOperationException("不允许在同一个区域中添加的重复服务项");
            }
            throw e;
        }

//        serveUpsertReqDTOList.forEach(serveUpsertReqDTO -> {
//            Serve serve = new Serve();
//            BeanUtils.copyProperties(serveUpsertReqDTO, serve);
//            Region region = regionService.getById(serveUpsertReqDTO.getRegionId());
//            serve.setCityCode(region.getCityCode());
//            this.save(serve);
//        });

    }

    @Override
    public Serve updatePriceById(Long id, BigDecimal price) {
        boolean update = lambdaUpdate().eq(Serve::getId, id)
                .set(Serve::getPrice, price)
                .update();
        if (!update) {
            throw new CommonException("修改服务价格失败");
        }
        return baseMapper.selectById(id);
    }

    @Override
    @Transactional
    public Serve onSale(Long id) {
        //获取要修改的服务并进行判断能否上架
        Serve serve = this.getById(id);
        if (ObjectUtils.isEmpty(serve)) {
            throw new ForbiddenOperationException("区域服务不存在");
        }

        if (serve.getSaleStatus() != FoundationStatusEnum.INIT.getStatus() && serve.getSaleStatus() != FoundationStatusEnum.DISABLE.getStatus()) {
            throw new ForbiddenOperationException("草稿或下架状态方可上架");
        }
        //获取对应的服务项并进行检查
        Long serveItemId = serve.getServeItemId();
        ServeItem serveItem = serveItemService.getById(serveItemId);
        if (ObjectUtil.isNull(serveItem)) {
            throw new ForbiddenOperationException("所属服务项不存在");
        }

        if (!(FoundationStatusEnum.ENABLE.getStatus() == serveItem.getActiveStatus())) {
            throw new ForbiddenOperationException("服务项为启用状态方可上架");
        }

        //更新上架状态
        boolean update = lambdaUpdate()
                .eq(Serve::getId, id)
                .set(Serve::getSaleStatus, FoundationStatusEnum.ENABLE.getStatus())
                .update();
        if (!update) {
            throw new CommonException("启动服务失败");
        }
        return baseMapper.selectById(id);
    }

    @Override
    public Serve deleteById(Long id) {
        //查询并判断是否为草稿
        Serve serve = getById(id);
        if (ObjectUtils.isEmpty(serve)) {
            throw new ForbiddenOperationException("服务不存在");
        }
        if (serve.getSaleStatus() != 0) {
            throw new ForbiddenOperationException("只能删除草稿服务");
        }
        //删除
        boolean delete = removeById(id);
        if (!delete) {
            throw new CommonException("删除服务失败");
        }
        return serve;
    }

    @Override
    @Transactional
    public Serve offSale(Long id) {
        //获取要修改的服务并进行判断能否下架
        Serve serve = this.getById(id);
        if (ObjectUtils.isEmpty(serve)) {
            throw new ForbiddenOperationException("区域服务不存在");
        }

        if (serve.getSaleStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            throw new ForbiddenOperationException("上架状态方可下架");
        }

        //更新下架状态
        boolean update = lambdaUpdate()
                .eq(Serve::getId, id)
                .set(Serve::getSaleStatus, FoundationStatusEnum.DISABLE.getStatus())
                .update();
        if (!update) {
            throw new CommonException("下架服务失败");
        }
        return baseMapper.selectById(id);
    }

    @Override
    @Transactional
    public Serve onHot(Long id) {
        //获取要修改的服务并进行判断能否设置热门
        Serve serve = this.getById(id);
        if (ObjectUtils.isEmpty(serve)) {
            throw new ForbiddenOperationException("区域服务不存在");
        }

        if (serve.getSaleStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            throw new ForbiddenOperationException("服务未上架");
        }

        if (serve.getIsHot() == 1) {
            throw new ForbiddenOperationException("区域服务已是热门服务");
        }

        //设置热门服务
        boolean update = lambdaUpdate()
                .eq(Serve::getId, id)
                .set(Serve::getIsHot, 1)
                .update();
        if (!update) {
            throw new CommonException("设置热门服务失败");
        }
        return baseMapper.selectById(id);
    }

    @Override
    public Serve offHot(Long id) {
        //获取要修改的服务并进行判断能否取消热门
        Serve serve = this.getById(id);
        if (ObjectUtils.isEmpty(serve)) {
            throw new ForbiddenOperationException("区域服务不存在");
        }

        if (serve.getIsHot() == 0) {
            throw new ForbiddenOperationException("区域服务不是热门服务");
        }

        //设置热门服务
        boolean update = lambdaUpdate()
                .eq(Serve::getId, id)
                .set(Serve::getIsHot, 0)
                .update();
        if (!update) {
            throw new CommonException("取消热门服务失败");
        }
        return baseMapper.selectById(id);
    }
}
